package rank

import (
	"gddgame.cc/galaxy/utils"
	"github.com/gomodule/redigo/redis"
)

type Redis struct {
	redisPool *redis.Pool
}

func NewRedis(pool *redis.Pool) *Redis {
	r := &Redis{
		redisPool: pool,
	}
	return r
}

func (redis *Redis) Update(prefix string, key string, value int) error {
	r := redis.redisPool.Get()
	defer r.Close()
	if err := r.Send("zadd", prefix, value, key); err != nil {
		return err
	}
	return nil
}

func (redis *Redis) Score(prefix string, key string) int {
	r := redis.redisPool.Get()
	defer r.Close()
	rr, err := r.Do("zscore", prefix)
	if err != nil {
		return 0
	}
	return utils.ToInt(rr)
}

func (redis *Redis) Count(prefix string) int {
	r := redis.redisPool.Get()
	defer r.Close()
	rr, err := r.Do("zcard", prefix)
	if err != nil {
		return 0
	}
	return utils.ToInt(rr)
}

func (redis *Redis) Rank(prefix string, key string, asc bool) int {
	var command string
	if asc {
		command = "zrank"
	} else {
		command = "ZREVRANK"
	}
	r := redis.redisPool.Get()
	defer r.Close()
	rr, err := r.Do(command, prefix, key)
	if err != nil || rr == nil {
		return 0
	}
	// redis统计从0开始
	return utils.ToInt(rr) + 1
}

func (redis *Redis) Top(prefix string, number int, asc bool) []Position {
	var command string
	if asc {
		command = "ZRANGE"
	} else {
		command = "ZREVRANGE"
	}
	r := redis.redisPool.Get()
	defer r.Close()
	var err error
	var rr interface{}
	rr, err = r.Do(command, prefix, 0, number-1, "WITHSCORES")
	if err != nil {
		return []Position{}
	}
	rrr := rr.([]interface{})
	d := make([]Position, 0, len(rrr)/2)
	for i := 0; i < len(rrr); i += 2 {
		key := utils.ToString(rrr[i])
		value := utils.ToInt(utils.ToString(rrr[i+1]))
		d = append(d, Position{
			Rank:  i/2 + 1,
			Key:   key,
			Value: value,
		})
	}
	return d
}

func (redis *Redis) Range(prefix string, start int, end int, number int, asc bool) []Position {
	var command string
	if asc {
		command = "ZRANGEBYSCORE"
	} else {
		command = "ZREVRANGEBYSCORE"
		tmp := start
		start = end
		end = tmp
	}
	r := redis.redisPool.Get()
	defer r.Close()
	var err error
	var rr interface{}
	rr, err = r.Do(command, prefix, start, end, "WITHSCORES", "LIMIT", 0, number)
	if err != nil {
		return []Position{}
	}
	rrr := rr.([]interface{})
	d := make([]Position, 0, len(rrr)/2)
	for i := 0; i < len(rrr); i += 2 {
		key := utils.ToString(rrr[i])
		value := utils.ToInt(rrr[i+1])
		d = append(d, Position{
			Rank:  i/2 + 1,
			Key:   key,
			Value: value,
		})
	}
	return d
}
